import TimerComponent from "../Timer/TimerComponent";

export default class SessionStorageComponent implements Chaos.IDisposable {
    private static instance: SessionStorageComponent = new SessionStorageComponent();
    public static get Default(): SessionStorageComponent {
        return this.instance;
    }

    constructor() {
        window.addEventListener('unload', this.Dispose.bind(this));
    }

    Dispose() {
        window.removeEventListener('unload', this.Dispose);
    }

    public static readonly CommandLineArgsKey: string = 'CommandLineArgs';

    /**
     * 等待指定键出现
     * @param key 键
     * @param interval 刷新间隔
     * @param timeout 超时时间
     * @returns 值
     */
    public async ReadAsync(key: string, interval: number = 100, timeout: number | undefined = undefined): Promise<string | null> {
        let value: string | null = window.sessionStorage.getItem(key);
        while (value == null) {
            if (timeout != undefined && timeout < 0) {
                break;
            }

            await TimerComponent.Default.WaitAsync(interval);
            value = window.sessionStorage.getItem(key);

            if (timeout != undefined) {
                timeout -= interval;
            }
        }
        return value;
    }

    /**
     * 等待指定键出现
     * @param key 键
     * @param interval 刷新间隔
     * @param timeout 超时时间
     * @returns 值
     * @description 该方法为解析嵌套Json采用eval, 存在注入攻击风险
     */
    public async ReadAsAsync<T extends Object>(key: string, interval: number = 100, timeout: number | undefined = undefined): Promise<T | null> {
        const content = await this.ReadAsync(key, interval, timeout);
        if (content != null) {
            try {
                const parsed = JSON.parse(content) as T;
                if (parsed != null) {
                    return parsed;
                }
            } catch (error) {
                return null;
            }
        }

        return null;
    }

    /**
     * 添加键值对
     * @param key 键
     * @param value 值
     */
    public Add<TValue extends Object>(key: string, value: string | TValue): void {
        if (typeof value === 'string') {
            window.sessionStorage.setItem(key, value);
        } else {
            window.sessionStorage.setItem(key, JSON.stringify(value));
        }
    }

    /**
     * 根据键读取值
     * @param key 键
     * @returns 值
     */
    public Read(key: string): string {
        const value = window.sessionStorage.getItem(key);
        if (value == null) {
            throw new Error(`指定键(${key})不存在`);
        }
        return value;
    }

    /**
     * 根据键读取值
     * @param key 键
     * @returns 值
     */
    public ReadAs<TValue extends Object>(key: string): TValue {
        const value = window.sessionStorage.getItem(key);
        if (value == null) {
            throw new Error(`指定键(${key})不存在`);
        }
        return JSON.parse(value) as TValue;
    }

    /**
     * 指定键是否存在
     * @param key 键
     */
    public Contains(key: string): boolean {
        return window.sessionStorage.getItem(key) != null;
    }

    /**
     * 移除键
     * @param key 键
     */
    public Remove(key: string): void {
        window.sessionStorage.removeItem(key);
    }
}